package cmd

import (
	"bytes"
	"context"
	"fmt"
	// "net/url"
	// "gitee.com/quantum-force/of-generic/safe"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/chromedp"
	"strconv"
)

type SearchResultInfo struct {
	CityName string     `json:"city"`
	Keyword  string     `json:"keyword"`
	Shopes   []ShopItem `json:"shopes"`
}

type ShopItem struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

func (tr *TaskRunner) SearchByKeyword(city City, keyword string) *TaskRunner {
	tr.searchResultInfo.CityName = city.String2()
	tr.searchResultInfo.Keyword = keyword
	// refererUrl := fmt.Sprintf("%s/%s", dpHost, city.String3())
	// 智能排序
	searchKeywordUrl := fmt.Sprintf(`%s/search/keyword/%s/0_%s`, dpHost, city, keyword) //url.QueryEscape(keyword)
	const selNotFound = `body > div.section.Fix.J-shop-search > div.content-wrap > div.shop-wrap > div.not-found`
	const selNextBtn = `body > div.section.Fix.J-shop-search > div.content-wrap > div.shop-wrap > div.page > a.next`
	const selPageBtn = `body > div.section.Fix.J-shop-search > div.content-wrap > div.shop-wrap > div.page > a.PageLink`
	const selShopItem = `#shop-all-list > ul > li > div.txt > div.tit > a[data-hippo-type]`
	isBreak := false
	currentPage := 1
	maxPage := 1
	var pageBtnNodes []*cdp.Node
	tr.Navigate(searchKeywordUrl)
	tr.tasks = append(tr.tasks, chromedp.Tasks{
		IfPresentOrElse(
			selNotFound,
			Sequence(
				chromedp.ActionFunc(func(ctx context.Context) error {
					fmt.Printf("not found any shop for keyword => %s @ %s\n", keyword, city.String2())
					return nil
				}),
			),
			Sequence(
				FindNodes(selPageBtn, &pageBtnNodes),
				chromedp.ActionFunc(func(ctx context.Context) error {
					if len(pageBtnNodes) > 0 {
						lastNode := pageBtnNodes[len(pageBtnNodes)-1]
						maxPage, _ = strconv.Atoi(lastNode.AttributeValue("title"))
						slog.Debugf("获取分页中的总页数(%d)", maxPage)
					} else {
						slog.Debug("数据仅当前页一页..")
					}
					return nil
				}),
				Loop(
					BreakCheckFunc(func(ctx context.Context) bool {
						nextUrl := fmt.Sprintf("%s/p%d", searchKeywordUrl, currentPage+1)
						slog.Debugln(nextUrl)
						err := chromedp.Run(ctx,
							IfPresentOrElse(selNextBtn,
								// 显示nextBtn,表示还有下一页
								Sequence(
									chromedp.ActionFunc(func(ctx context.Context) error {
										slog.Debugln("显示nextBtn表示还有下一页,随机停止n秒后跳转到下一页")
										return nil
									}),
									tr.wait(randOver(2, 5)),
									chromedp.Navigate(nextUrl),
									// tr.navigateWithRefererAction(
									// 	fmt.Sprintf("%s/p%d", searchKeywordUrl, currentPage+1),
									// 	IIF(currentPage == 1, searchKeywordUrl, fmt.Sprintf("%s/p%d", searchKeywordUrl, currentPage)),
									// ),
								),
								// 已经是最后一页了,跳出循环
								Sequence(
									chromedp.ActionFunc(func(ctx context.Context) error {
										if currentPage < maxPage {
											slog.Debugf("还没到达最后一页,但是被dp网站监测没有返回当页(%d)数据", currentPage)
										} else {
											slog.Debugln("已经是最后一页了,跳出循环")
											isBreak = true
										}
										return nil
									}),
								),
							))
						if err != nil {
							slog.Errorf("check breaker err=>%s,提前跳出循环", err)
							return true
						}
						slog.Debugf("判定isBreak=>%v", isBreak)
						currentPage++
						return isBreak
					}),
					chromedp.ActionFunc(func(ctx context.Context) error {
						err := chromedp.Run(ctx,
							Iter(
								selShopItem,
								IterNodeNextFunc(func(ctx context.Context, idx int, node *cdp.Node) chromedp.Action {
									tr.searchResultInfo.Shopes = append(tr.searchResultInfo.Shopes,
										ShopItem{
											ID:   node.AttributeValue("data-shopid"),
											Name: node.AttributeValue("title"),
										})
									return Noop()
								}),
								IterDoneFunc(func(ctx context.Context, _ bool) chromedp.Action {
									return chromedp.ActionFunc(func(ctx context.Context) error {
										slog.Debugf("page(%d) processed!", currentPage)
										return nil
									})
								}),
								IterNodeFilterFunc(func(ctx context.Context, idx int, node *cdp.Node) bool {
									var istopTrade bool
									if err := chromedp.Run(ctx,
										ExistNode(`span.istopTrade`, &istopTrade, chromedp.FromNode(node.Parent)),
									); err != nil {
										slog.Errorf("istopTrade node check exist err(%d)=>%s", idx, err)
										return false
									}
									slog.Debugf("istopTrade:%v\n", istopTrade)
									return !istopTrade
								}),
							),
						)
						if err != nil {
							return err
						}
						return nil
					}),
				),
			),
		),
	})
	return tr
}

func (tr *TaskRunner) dumpTmpShopItemList(file string) (err error) {
	bu := new(bytes.Buffer)
	for _, item := range tr.searchResultInfo.Shopes {
		bu.WriteString(dpHost)
		bu.WriteString("/shop/")
		bu.WriteString(item.ID)
		bu.WriteByte(0x0A) // \n
	}
	tr.srMu.Lock()
	defer tr.srMu.Unlock()
	err = tr.WriteFile(file, bu)
	return
}

func (tr *TaskRunner) DumpSearchResult() *TaskRunner {
	tr.tasks = append(tr.tasks,
		chromedp.ActionFunc(func(ctx context.Context) error {
			err := tr.dumpTmpShopItemList(fmt.Sprintf("tmp/%s_%s.txt", tr.searchResultInfo.CityName, tr.searchResultInfo.Keyword))
			if err != nil {
				return err
			}
			return tr.dumpToFile(fmt.Sprintf("crawled/search/%s_%s.json", tr.searchResultInfo.CityName, tr.searchResultInfo.Keyword), tr.searchResultInfo)
		}),
	)
	return tr
}

func (tr *TaskRunner) SearchResultReset() *TaskRunner {
	tr.tasks = append(tr.tasks,
		chromedp.ActionFunc(func(ctx context.Context) error {
			tr.searchResultInfo.CityName = ""
			tr.searchResultInfo.Keyword = ""
			tr.searchResultInfo.Shopes = nil
			return nil
		}),
	)
	return tr.Reset()
}
